package com.longtop.sp.mapdao.dialect.mysql;

import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import com.longtop.sp.mapdao.meta.AbstractPrimaryKey;
import com.longtop.sp.mapdao.meta.TableMetaData;

public class MysqlPrimaryKey extends AbstractPrimaryKey{
	
	private static Log log = LogFactory.getLog(MysqlPrimaryKey.class);
	
	private List lstPrimaryKey = null;
	
	public MysqlPrimaryKey(JdbcTemplate jt, String tableName)
			throws SQLException {
		lstPrimaryKey = executeSearch(jt, tableName);
	}
	
	/**
	 * 获取主键数据，此部分与数据库相关，不同的数据库需要查询不同的数据字典
	 * 
	 * @param conn
	 *            数据库链接
	 * @param tableName
	 *            表名
	 * @return 返回表的主键列名列表，列名为大写
	 * @throws SQLException
	 */
	private List executeSearch(JdbcTemplate jt, String tableName) throws SQLException {
		List lst = new ArrayList();
		/**
		 * 一般都是查询自己的表，也有可能操作别人的表。如果是操作别人的表，应查讯All_CONSTRAINTS C, All_IND_COLUMNS
		 * IC，并且加上OWNER条件
		 */
		int dot = tableName.indexOf('.');
		String sql;
		if (dot > 0 && dot != tableName.length() - 1) { // .不在第一个或最后一个
			String owner = tableName.substring(0, dot);
			tableName = tableName.substring(dot + 1);
			sql = "SELECT"
					+ " c.COLUMN_NAME,c.ORDINAL_POSITION"
					+ " FROM "
					+ "INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t,"
					+ "INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c"
					+ " WHERE"
					+ " t.TABLE_NAME = c.TABLE_NAME"
					+ " AND t.CONSTRAINT_NAME = c.CONSTRAINT_NAME"
					+ " AND t.TABLE_SCHEMA = '"+owner.toUpperCase()+"'"
					+ " AND t.TABLE_NAME = '" + tableName.toUpperCase() + "'"
					+ " AND t.CONSTRAINT_TYPE = 'PRIMARY KEY'"
					+ " GROUP BY "
					+ "c.COLUMN_NAME,"
					+ "c.ORDINAL_POSITION"
					+ "ORDER BY"
					+ "	c.COLUMN_NAME DESC";
					
		} else {
			sql = "SELECT TABLE_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE"
				+ " WHERE TABLE_NAME <> 'dtproperties'"
				+ " AND table_name = '" + tableName.toLowerCase() + "'";
		}
		if (log.isDebugEnabled()) {
			log.debug("获取Mysql主键sql=" + sql);
		}
		List<Map> rs = jt.queryForList(sql);
		if (rs != null && !rs.isEmpty()) {
			for (Map map : rs) {
				lst.add((String) map.get("COLUMN_NAME"));
			}
		}
		if (lst.size() == 0) {
			throw new SQLException("您指定的表" + tableName + "不存在，或者没有主键，不能处理！");
		}
		
		return lst;
	}

	@Override
	public String getPrimaryKey(int idx) {
		return (String) lstPrimaryKey.get(idx);
	}

	@Override
	public int size() {
		return lstPrimaryKey.size();
	}
	/**
	 * @param tmRowData
	 *            包含字段名-值对的Map，使用ComparatorIgnoreCase的TreeMap，以便key不区分大小写。
	 * @return 主键和对应的值，可用来定位纪录
	 * @throws SQLException
	 */
	@Override
	public String getPrimaryKeyAndValue(Map tmRowData, TableMetaData rsmt) throws SQLException {
		StringBuffer pkAndValue = new StringBuffer(); // 主键和对应的值，可用来定位纪录
		for (int i = 0; i < lstPrimaryKey.size(); i++) {
			if (i != 0) {
				pkAndValue.append(" AND ");
			}
			String key = (String) lstPrimaryKey.get(i);
			Object o = tmRowData.get(key);
			if (o == null) {
				String msg = "主键" + key + "在HashMap中没有对应数据";
				log.info(msg);
				throw new SQLException(msg);
			}
			for (int j = 1, m = rsmt.getColumnCount(); j <= m; j++) {
				// key是从字典表中查出的，全部是大写，rsmtc.getName(j)也是大写，所以，不需要ignore case。
				if (key.equals(rsmt.getName(j))) {
					int t = rsmt.getType(j);
					if (t == Types.BIGINT || t == Types.BIT
							|| t == Types.DECIMAL || t == Types.DOUBLE
							|| t == Types.FLOAT || t == Types.INTEGER
							|| t == Types.NUMERIC || t == Types.REAL
							|| t == Types.SMALLINT || t == Types.TINYINT) {
						pkAndValue.append(key + "=" + o.toString());
					}
					// data is primary key
					else if (t == Types.DATE || t == Types.TIME
							|| t == Types.TIMESTAMP) {
						/**
						 * @todo //pkAndValue.append(key + "=" +
						 *       convert2DataStr(o));
						 */
						// pkAndValue.append(key + "=" + convert2DataStr(o));
					} else {
						pkAndValue.append(key + "='" + o.toString() + "'");
					}
					break;
				}
				if (j == m) { // 一直都没有找到此主键，应该不会发生这种情况，除非主键有问题
					String msg = "主键" + key + "在数据库表中没有对应字段。";
					log.warn(msg);
					throw new SQLException(msg);
				}
			}
		}
		return new String(pkAndValue);
	}

}
